package org.rayken.trix.commons.game.runTypes;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.rayken.trix.commons.card.Card;
import org.rayken.trix.commons.card.Rank;
import org.rayken.trix.commons.card.Suit;
import org.rayken.trix.commons.game.Game;
import org.rayken.trix.commons.game.Player;
import org.rayken.trix.commons.game.Run;
import org.rayken.trix.commons.game.RunType;
import org.rayken.trix.commons.game.Trick;

/**
 * It's up to the class user to implement player replay when he plays an ace or
 * a seven.
 * 
 * @author E-Kraiem-A
 * 
 */
public class TrixRun extends Run {

	private static class TopBottom {
		private Rank top = null;// To Ace
		private Rank bottom = null;// To Seven

		public Rank getTop() {
			return top;
		}

		public void setTop(Rank top) {
			this.top = top;
		}

		public Rank getBottom() {
			return bottom;
		}

		public void setBottom(Rank bottom) {
			this.bottom = bottom;
		}

		@Override
		public String toString() {
			return bottom + "-" + top;
		}
		
	}

	private Map<Suit, TopBottom> board = new HashMap<Suit, TopBottom>();

	protected TrixRun(Game game, Player caller, boolean forced) {
		super(game, caller, forced);
		board.put(Suit.CLUBS, new TopBottom());
		board.put(Suit.DIAMONDS, new TopBottom());
		board.put(Suit.HEARTS, new TopBottom());
		board.put(Suit.SPADES, new TopBottom());
	}

	static final int FIRST_SCORE = -100;
	static final int SECOND_SCORE = -50;
	private int playersFinished = 0;

	@Override
	public boolean isFinished() {
		return playersFinished == 2;
	}

	@Override
	public RunType getType() {
		return RunType.TRIX;
	}

	@Override
	public void cardPlayed(Player player, Trick turn, Card cardPlayed) {
		deals.get(player).remove(cardPlayed);
		// Update board
		if (cardPlayed.getRank() == Rank.JACK) {
			board.get(cardPlayed.getSuit()).setTop(Rank.JACK);
			board.get(cardPlayed.getSuit()).setBottom(Rank.JACK);
		}
		if (cardPlayed.getRank().getRank() > Rank.JACK.getRank())
			board.get(cardPlayed.getSuit()).setTop(cardPlayed.getRank());
		else
			board.get(cardPlayed.getSuit()).setBottom(cardPlayed.getRank());

		assert playersFinished < 2;
		if (deals.get(player).size() == 0) {
			playersFinished++;
			int scoreToAdd;
			if (playersFinished == 1) {
				scoreToAdd = FIRST_SCORE;
			} else
				scoreToAdd = SECOND_SCORE;
			if (player.equals(caller))
				scoreToAdd *= 2;
			if (forced)
				scoreToAdd *= 2;

			addScore(player, scoreToAdd);
		}

	}

	@Override
	public List<Card> getAvailablePlayableCard(Player player, Trick turn) {
		List<Card> playable = new ArrayList<Card>();
		List<Card> cardsInHand = deals.get(player);
		for (Card card : cardsInHand) {
			if (card.getRank() == Rank.JACK)
				playable.add(card);
			Rank top = board.get(card.getSuit()).getTop();
			Rank bottom = board.get(card.getSuit()).getBottom();
			if (top != null && bottom != null) {
				if (card.getRank().getRank() == top.getRank() + 1)
					playable.add(card);
				if (card.getRank().getRank() == bottom.getRank() - 1)
					playable.add(card);
			}
		}
		return playable;
	}

}
